package cn.bupt.adt.service.impl;

import cn.bupt.adt.constant.Constants;
import cn.bupt.adt.dao.autogenerate.*;
import cn.bupt.adt.entity.autogenerate.*;
import cn.bupt.adt.model.OperationContent;
import cn.bupt.adt.service.IDoctorAppUserService;
import cn.bupt.adt.service.IDoctorService;
import cn.bupt.adt.service.IInstitutionAppUserService;
import cn.bupt.adt.service.IOrderService;
import cn.bupt.adt.util.BeanUtil;
import cn.bupt.adt.util.ImageUtil;
import cn.bupt.adt.util.MyTask;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class OrderService implements IOrderService {

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    IDoctorAppUserService doctorAppUserService;

    @Autowired
    OrderViewMapper orderViewMapper;

    @Autowired
    DoctorAppUserMapper doctorAppUserMapper;

    @Autowired
    Doctor_OperationTypeMapper doctor_OperationTypeMapper;

    @Autowired
    IInstitutionAppUserService institutionService;

    @Autowired
    InstitutionAppUserMapper institutionAppUserMapper;

    @Autowired
    IDoctorService doctorService;

    @Autowired
    ObjectMapper objectMapper;

    @Override
    public boolean addOrder(Order order, IDoctorService doctorService) {
        ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(1);
        // 添加订单
        int i = orderMapper.insert(order);
        InstitutionAppUser ins = institutionAppUserMapper.selectByPrimaryKey(order.getInstitutionId());
        ins.setPublishOrderNum(ins.getPublishOrderNum() + 1);
        // 更新机构发单数量
        int j = institutionAppUserMapper.updateByPrimaryKeySelective(ins);
        timer.scheduleAtFixedRate(new MyTask(new Date(), timer, this, order.getId(), doctorService), 0, 1,
                TimeUnit.MINUTES);
        return i == 1 && j == 1;
    }

    @Override
    public List<OrderView> getAllOrders() {
        return orderViewMapper.selectByExampleWithBLOBs(new OrderViewExample());
    }

    @Override
    public List<OrderView> getOverTimeOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_UNTAKED).andPublishStatusEqualTo(Constants.OVER20);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getUntakedOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_UNTAKED);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getTakedAndUnoperatedOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_TAKEDNOTOPER);
        // ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_TAKEDNOTOPEROverTime);
        Date nowDate = new Date();// 当前时间\r
        long nowTime = nowDate.getTime();
        for (int i = 0; i < orderViewMapper.selectByExampleWithBLOBs(ex).size(); i++) {
            Order order = getOrderById(orderViewMapper.selectByExampleWithBLOBs(ex).get(i).getId());
            if (nowTime - orderViewMapper.selectByExampleWithBLOBs(ex).get(i).getStartTime().getTime() > 0) {
                long compareTime = nowTime
                        - orderViewMapper.selectByExampleWithBLOBs(ex).get(i).getStartTime().getTime();
                System.out.println("时间差==" + compareTime);
                order.setUnOpOverTime(1);
            } else {
                order.setUnOpOverTime(0);
            }
            orderMapper.updateByPrimaryKeySelective(order);
        }
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getTakedAndOperatingOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_TAKEDINOPERATION);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getTakedAndFinishedOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_TAKEDANDFINISHED);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getTakedAndAskForHelpOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_TAKEDANDASKFORHELP);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getFinishedOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_FINISHED);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getChangedOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_BIANDONG);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public List<OrderView> getCanceledOrders() {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_CANCELED);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public OrderView getOrderViewById(int id) {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andIdEqualTo(id);
        return orderViewMapper.selectByExampleWithBLOBs(ex).get(0);
    }

    @Override
    public List<OrderView> getOrderByInstitutionId(Integer userId) {
        OrderViewExample ex = new OrderViewExample();
        ex.createCriteria().andInstitutionIdEqualTo(userId);
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    @Override
    public Map<String, Object> getCanTakedOrdersByDoctorId(Integer userId, int pageNum, int pageSize,
                                                           HttpServletRequest request) {
        Doctor_OperationTypeExample ex = new Doctor_OperationTypeExample();
        DoctorAppUserExample dex = new DoctorAppUserExample();
        dex.createCriteria().andIdEqualTo(userId);
        DoctorAppUser doc = doctorAppUserService.getDoctorById(userId);
        ex.createCriteria().andDoctorIdEqualTo(doc.getId());
        List<Doctor_OperationType> Doc_types = doctor_OperationTypeMapper.selectByExample(ex);

        Map<String, Object> content = new HashMap<>();
        // 该医生没有任何手术标签
        if (Doc_types.size() == 0) {
            return content;
        }
        // 正常流程
        List<Integer> typeIds = new LinkedList<Integer>();
        // typeIds包含所有一级手术id
        for (Doctor_OperationType dot : Doc_types)
            typeIds.add(dot.getOperationTypeId());
        // 根据一级手术id找所有二级手术
        List<SubOperationType> subOperationTypes = doctorService.getSubOperationTypeByParentIds(typeIds);
        typeIds.clear();
        // typeIds包含所有二级手术id
        for (SubOperationType subOperationType : subOperationTypes)
            typeIds.add(subOperationType.getId());
        if (typeIds.size() == 0)
            return content;
        OrderViewExample oe = new OrderViewExample();
        // 1 未被接过的
        oe.or().andSubOperationTypeIdIn(typeIds).andStatusEqualTo(Constants.ORDER_STATUS_UNTAKED);
        // 2 医生取消的
        oe.or().andSubOperationTypeIdIn(typeIds).andStatusEqualTo(Constants.ORDER_STATUS_CANCELED)
                .andCancelByEqualTo(Constants.CANCEL_BY_DOC);
        Page<?> page = PageHelper.startPage(pageNum, pageSize);
        oe.setOrderByClause("id desc");
        List<OrderView> orders = orderViewMapper.selectByExampleWithBLOBs(oe);

        List<Map<String, Object>> res = new ArrayList<>();
        for (OrderView or : orders) {
            Map<String, Object> orModel = null;
            try {
                orModel = BeanUtil.beanToMap(or);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
                return content;
            }
            orModel.put("portrait", ImageUtil.contructFullImagePath(or.getPortrait(), request));
            try {
                orModel.put("operationContent",
                        objectMapper.readValue(or.getOperationContent(), new TypeReference<List<OperationContent>>() {
                        }));
            } catch (IOException e) {
                e.printStackTrace();
                return content;
            }
            res.add(orModel);
        }
        content.put("orders", res);
        content.put("currentPage", page.getPageNum());
        content.put("allPages", page.getPages());
        return content;
    }

    @Override
    public Map<String, Object> getUndoOrdersByDoctorId(Integer userId, int pageNum, int pageSize,
                                                       HttpServletRequest request) throws IllegalArgumentException, IllegalAccessException, IOException {
        Doctor_OperationTypeExample ex = new Doctor_OperationTypeExample();
        DoctorAppUserExample dex = new DoctorAppUserExample();
        dex.createCriteria().andIdEqualTo(userId);
        DoctorAppUser doc = doctorAppUserMapper.selectByExample(dex).get(0);
        ex.createCriteria().andIdEqualTo(doc.getId());
        OrderViewExample oe = new OrderViewExample();
        oe.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_TAKEDNOTOPER);
        Page<?> page = PageHelper.startPage(pageNum, pageSize);
        List<OrderView> orders = orderViewMapper.selectByExampleWithBLOBs(oe);
        Map<String, Object> content = new HashMap<String, Object>();
        List<Map<String, Object>> res = new ArrayList<>(orders.size());
        for (OrderView or : orders) {
            or.setPortrait(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/"
                    + Constants.IMAGE_PATH + or.getPortrait());
            String operationContent = or.getOperationContent();
            if (operationContent != null && operationContent.length() > 2) {
                Map<String, Object> orderModel = BeanUtil.beanToMap(or);
                orderModel.put("operationContent",
                        objectMapper.readValue(or.getOperationContent(), new TypeReference<List<OperationContent>>() {
                        }));
                res.add(orderModel);
            }
        }
        content.put("orders", res);
        content.put("currentPage", page.getPageNum());
        content.put("allPages", page.getPages());
        return content;
    }

    @Override
    public Map<String, Object> getUnfinishOrdersByDoctorId(Integer userId, int pageNum, int pageSize, HttpServletRequest request) throws IllegalAccessException, IOException {
        Doctor_OperationTypeExample ex = new Doctor_OperationTypeExample();
        DoctorAppUserExample dex = new DoctorAppUserExample();
        dex.createCriteria().andIdEqualTo(userId);
        DoctorAppUser doc = doctorAppUserMapper.selectByExample(dex).get(0);
        ex.createCriteria().andDoctorIdEqualTo(doc.getId());
        OrderViewExample oe = new OrderViewExample();
        oe.createCriteria().andStatusEqualTo(Constants.ORDER_STATUS_TAKEDINOPERATION);
        Page<?> page = PageHelper.startPage(pageNum, pageSize);
        Map<String, Object> content = new HashMap<>();
        List<OrderView> orders = orderViewMapper.selectByExampleWithBLOBs(oe);
        List<Map<String, Object>> res = new ArrayList<>(orders.size());
        for (OrderView or : orders) {
            or.setPortrait(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/"
                    + Constants.IMAGE_PATH + or.getPortrait());
            String operationContent = or.getOperationContent();
            if (operationContent != null && operationContent.length() > 2) {
                Map<String, Object> orderModel = BeanUtil.beanToMap(or);
                orderModel.put("operationContent",
                        objectMapper.readValue(or.getOperationContent(), new TypeReference<List<OperationContent>>() {
                        }));
                res.add(orderModel);
            }
        }
        content.put("orders", res);
        content.put("currentPage", page.getPageNum());
        content.put("allPages", page.getPages());
        return content;
    }

    @Override
    public Map<String, Object> getDoneOrdersByDoctorId(Integer userId, int pageNum, int pageSize, HttpServletRequest request) throws IOException, IllegalAccessException {
        OrderViewExample oe = new OrderViewExample();
        oe.setOrderByClause("startTime desc");
        oe.createCriteria().andDoctorIdEqualTo(userId).andStatusEqualTo(Constants.ORDER_STATUS_TAKEDANDFINISHED);
        Page<?> page = PageHelper.startPage(pageNum, pageSize);
        Map<String, Object> content = new HashMap<>();
        List<OrderView> orders = orderViewMapper.selectByExampleWithBLOBs(oe);
        List<Map<String, Object>> res = new ArrayList<>(orders.size());
        for (OrderView or : orders) {
            or.setPortrait(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/"
                    + Constants.IMAGE_PATH + or.getPortrait());
            String operationContent = or.getOperationContent();
            if (operationContent != null && operationContent.length() > 2) {
                Map<String, Object> orderModel = BeanUtil.beanToMap(or);
                orderModel.put("operationContent",
                        objectMapper.readValue(or.getOperationContent(), new TypeReference<List<OperationContent>>() {
                        }));
                res.add(orderModel);
            }
        }
        content.put("orders", res);
        content.put("currentPage", page.getPageNum());
        content.put("allPages", page.getPages());
        return content;
    }

    @Override
    public void updateOrderByPrimarykeySelective(Order order) {
        orderMapper.updateByPrimaryKeySelective(order);
    }

    @Override
    public Order getOrderById(int id) {
        return orderMapper.selectByPrimaryKey(id);
    }

    @Override
    public boolean updateOrder(Order order) {
        Integer rs = 0;
        try {
            if (order.getStatus() == 3) {
                order.setEndTime(new Date());
                rs = orderMapper.updateByPrimaryKeySelective(order);
            } else if (order.getStatus() == 2) {
                Calendar cal = Calendar.getInstance();
                Date dateStart = getOrderById(order.getId()).getStartTime();
                Calendar calStart = Calendar.getInstance();
                calStart.setTime(dateStart);
                Integer day = cal.get(Calendar.DATE);
                Integer dayStart = calStart.get(Calendar.DATE);
                // System.out.println("点击开始时间=="+day);
                // System.out.println("预计开始时间=="+dayStart);
                if (day == dayStart) {
                    rs = orderMapper.updateByPrimaryKeySelective(order);
                } else {
                    return false;
                }
            } else {
                rs = orderMapper.updateByPrimaryKeySelective(order);
            }
            if (rs != 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public boolean instiUpdateOrder(Order order) {
        try {
            order.setStatus(6);
            DoctorAppUser doc = doctorAppUserService.getDoctorById(getOrderById(order.getId()).getDoctorId());
            doc.setMoney(getOrderById(order.getId()).getMoney() + doc.getMoney());
            doctorAppUserService.updateDoctorAppuser(doc);
            Integer rs = orderMapper.updateByPrimaryKeySelective(order);
            if (rs != 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public boolean cancelOrder(Order order, Integer id) {
        try {
            order.setStatus(5);
            order.setCancelBy(true);
            order.setDoctorId(-1);
            order.setCancelTime(new Date());
            int rs = orderMapper.updateByPrimaryKeySelective(order);
            if (rs != 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public boolean cancelOrderByInst(Order order) {
        try {
            order.setStatus(5);
            order.setCancelBy(false);
            order.setCancelTime(new Date());
            int rs = orderMapper.updateByPrimaryKeySelective(order);

            if (rs != 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public boolean takeOrder(int orderId, Integer userId) {
        Order order = getOrderById(orderId);
        DoctorAppUser doc = doctorAppUserService.getDoctorById(userId);
        if ((order.getDoctorId() != null && order.getDoctorId() != -1) || !canBeTaken(order)
                || doc.getRiskMargin() < Constants.LEAST_REMAINS) {
            return false;
        } else {
            if (order.getStatus().equals(Constants.ORDER_STATUS_CANCELED)) {
                order.setCancelBy(null);
                order.setCancelReason("");
            }
            order.setDoctorId(userId);
            order.setStatus(Constants.ORDER_STATUS_TAKEDNOTOPER);
            int i = orderMapper.updateByPrimaryKeySelective(order);
            // return i == 1;
            return true;
        }
    }

    private boolean canBeTaken(Order order) {
        if (order == null) {
            return false;
        }
        boolean isUntaken = order.getStatus().equals(Constants.ORDER_STATUS_UNTAKED);
        boolean isCancelByDoctor = order.getStatus().equals(Constants.ORDER_STATUS_CANCELED)
                && order.getCancelBy().equals(Constants.CANCEL_BY_DOC);
        return isUntaken || isCancelByDoctor;
    }

    @Override
    public List<OrderView> getOrderByInstitutionIdAndStatus(Integer userId, Integer status) {
        OrderViewExample ex = new OrderViewExample();
        ex.setOrderByClause("startTime desc");
        switch (status) {
            case 0:
                ex.or().andInstitutionIdEqualTo(userId).andStatusEqualTo(status);
                ex.or().andInstitutionIdEqualTo(userId).andStatusEqualTo(5).andCancelByEqualTo(Constants.CANCEL_BY_DOC);
                break;
            case 1:
                ex.createCriteria().andInstitutionIdEqualTo(userId).andStatusIn(
                        Arrays.asList(new Integer(1), new Integer(2), new Integer(3), new Integer(4), new Integer(7)));
                break;
            case 2:
                ex.or().andInstitutionIdEqualTo(userId).andStatusEqualTo(5).andCancelByEqualTo(Constants.CANCEL_BY_INS);
                ex.or().andInstitutionIdEqualTo(userId).andStatusEqualTo(new Integer(6));
                break;
            default:
                break;
        }
        return orderViewMapper.selectByExampleWithBLOBs(ex);
    }

    /**
     * 获取进行中的订单
     */
    @Override
    public Map<String, Object> getOnGoingOrdersOrdersByDoctorId(Integer userId, int pageNum, int pageSize, HttpServletRequest request) throws IllegalAccessException, IOException {
        OrderViewExample ex = new OrderViewExample();
        ex.setOrderByClause("startTime desc");
        ex.createCriteria().andDoctorIdEqualTo(userId).andStatusIn(Arrays.asList(new Integer(1), new Integer(2), new Integer(3), new Integer(7)));
        Map<String, Object> content = new HashMap<String, Object>();
        Page<?> page = PageHelper.startPage(pageNum, pageSize);
        List<OrderView> orders = orderViewMapper.selectByExampleWithBLOBs(ex);
        List<Map<String, Object>> res = new ArrayList<>(orders.size());
        for (OrderView or : orders) {
            or.setPortrait(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/"
                    + Constants.IMAGE_PATH + or.getPortrait());
            String operationContent = or.getOperationContent();
            if (operationContent != null && operationContent.length() > 2) {
                Map<String, Object> orderModel = BeanUtil.beanToMap(or);
                orderModel.put("operationContent",
                        objectMapper.readValue(or.getOperationContent(), new TypeReference<List<OperationContent>>() {
                        }));
                res.add(orderModel);
            }
        }
        content.put("orders", res);
        content.put("currentPage", page.getPageNum());
        content.put("allPages", page.getPages());
        return content;
    }

    @Override
    public Map<String, Object> getFinishedOrdersByDoctorId(Integer userId, int pageNum, int pageSize,
                                                           HttpServletRequest request) throws JsonParseException, JsonMappingException, IOException,
            IllegalArgumentException, IllegalAccessException {
        OrderViewExample ex = new OrderViewExample();
        ex.setOrderByClause("id desc");
        ex.createCriteria().andDoctorIdEqualTo(userId).andStatusEqualTo(Constants.ORDER_STATUS_FINISHED);
        Map<String, Object> content = new HashMap<String, Object>();
        Page<?> page = PageHelper.startPage(pageNum, pageSize);
        List<OrderView> orders = orderViewMapper.selectByExampleWithBLOBs(ex);
        List<Map<String, Object>> res = new ArrayList<>(orders.size());
        for (OrderView or : orders) {
            or.setPortrait(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/"
                    + Constants.IMAGE_PATH + or.getPortrait());
            String operationContent = or.getOperationContent();
            if (operationContent != null && operationContent.length() > 2) {
                Map<String, Object> orderModel = BeanUtil.beanToMap(or);
                orderModel.put("operationContent",
                        objectMapper.readValue(or.getOperationContent(), new TypeReference<List<OperationContent>>() {
                        }));
                res.add(orderModel);
            }
        }
        content.put("orders", res);
        content.put("currentPage", page.getPageNum());
        content.put("allPages", page.getPages());
        return content;
    }
}
